package yxy.game.pm2.gm.url;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import org.redisson.api.RLock;
import yxy.apple.http.server.business.Business;
import yxy.apple.http.server.business.BusinessType;
import yxy.apple.logger.Logger;
import yxy.apple.util.redisson.RedisConnection;
import yxy.cherry.game.base.bean.GatewayBean;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.cherry.game.base.redis.RedisType;
import yxy.game.pm2.active.module.actcontrol.activeControl;
import yxy.game.pm2.bean.ServerBean;
import yxy.game.pm2.bean.area.AreaBean;
import yxy.game.pm2.bean.cluster.ClusterBean;
import yxy.game.pm2.bean.db.dao.MySQLServerDAO;
import yxy.game.pm2.bean.db.module.server;
import yxy.game.pm2.gm.result.GMResult;
import yxy.game.pm2.gm.result.GMResult.GMError;
import yxy.game.pm2.gm.url.mergearea.MergeAreaHandle_冲榜排行榜;
import yxy.game.pm2.gm.url.mergearea.MergeAreaHandle_排行榜;
import yxy.game.pm2.gm.url.mergearea.MergeAreaHandle_排行进度;
import yxy.game.pm2.module.daily.DailyHandle;

/** 分区合并 */
@BusinessType(code = "MERGEAREA")
public class GMMergeArea implements Business {
	protected static Logger logger = Logger.create(GMMergeArea.class);

	@Override
	public String name() {
		return "gm";
	}

	@Override
	public JSONObject handle(JSONObject request) throws Exception {
		logger.info("request:%s", request);
		JSONObject result = new JSONObject();
		GMResult gmResult = new GMResult();

		JSONArray areas = request.getJSONArray("areas");// 需要合并的分区
		int mainAreaId = request.getIntValue("newArea");// 合并后的主区

		String lockKey = "MERGEAREA:" + mainAreaId; //锁

		try {
			if (!tryLock(lockKey)) return result;

			if (areas.size() < 2)
				throw new Exception("合并区数量必须大于或等于2");

			List<String> ids = areas.toJavaList(String.class);
			if (ids.indexOf(String.valueOf(mainAreaId)) == -1)
				throw new Exception("主区必须在要合并的区列表中");

			AreaBean mainAreaBean = AreaBean.get(mainAreaId);
			if (mainAreaBean == null)
				throw new Exception("主区不存在");

			//主区所在的专服
			ClusterBean clusterBean = ClusterBean.get(mainAreaBean.getClusterId());
			if (clusterBean == null) throw new Exception("专服不存在");

			ArrayList<AreaBean> areaBeanList = new ArrayList<>();
			checkArea(areas, areaBeanList, clusterBean);

			// 3 扫瞄是否还有合并区所属的玩家在线
			checkPlayers(areaBeanList);

			// 4 进行合并操作
			merge(mainAreaBean, areaBeanList);

			unlock(lockKey);
			return gmResult.result(new JSONObject(), GMError.OK);
		} catch (Exception e) {
			unlock(lockKey);
			e.printStackTrace();
			result.put("message", e.getMessage());
			return gmResult.result(result, GMError.Err_区合并_合并异常);
		}
	}

	private boolean checkNewArea(int newArea) {
		AreaBean areaBean = AreaBean.get(newArea);
		return areaBean == null;// 如果新区号不存在 则返回true
	}

	private JSONObject checkArea(JSONArray areas, ArrayList<AreaBean> areaBeanList, ClusterBean clusterBean) throws Exception {
		logger.info("checkArea,%s", areas);
		// 判断区号
		for (int i = 0; i < areas.size(); i++) {
			int areaId = areas.getIntValue(i);
			AreaBean areaBean = AreaBean.get(areaId);
			if (areaBean == null) {
				throw new Exception(areaId + "区不存在");
			}
			if (areaBean.isMeraged()) {
				areaBean.getGroupId();
				throw new Exception(areaId + "该区已经被合并");
			}
			if (areaBean.getClusterId() != clusterBean.getClusterId()) {
				throw new Exception(areaId + "该区跟主区不在同一专服");
			}
			areaBeanList.add(areaBean);
		}
		// 判断各区服务器状态
		for (AreaBean areaBean : areaBeanList) {
			for (String serverId : areaBean.getServerList()) {
				int sid = Integer.parseInt(serverId);
				ServerBean serverBean = ServerBean.get(sid);
				server db = MySQLServerDAO.get(sid);
				if (serverBean == null || db == null) {
					throw new Exception("该区的游戏服错误，areaid：" + areaBean.getAreaId() + "，serverid：" + sid);
				}
				if (db.getState() != 0) {
					throw new Exception("该区的游戏服未停服，areaid：" + areaBean.getAreaId() + "，serverid：" + sid);
				}
			}
		}

		return null;
	}

	private JSONObject checkPlayers(Collection<AreaBean> areas) throws Exception {
		ArrayList<String> serverIds = new ArrayList<>();
		for (AreaBean areaBean : areas) {
			serverIds.addAll(areaBean.getServerList());
		}
		Collection<GatewayBean> all = GatewayBean.all(RedisManager.getInstance().getConnection(RedisType.REDIS_USER));
		for (GatewayBean gatewayBean : all) {
			String serverId = String.valueOf(gatewayBean.getSid());
			if (serverIds.contains(serverId)) {
				throw new Exception("合并区有玩家在线，serverid：" + serverId);
			}
		}
		return null;
	}

	/**
	 * 合并执行
	 * 
	 * @throws Exception
	 */
	private void merge(AreaBean mainAreaBean, Collection<AreaBean> areas) throws Exception {
		ArrayList<String> serverIdList = new ArrayList<>();

		for (AreaBean areaBean : areas) {
			serverIdList.addAll(areaBean.getServerList());
			areaBean.getServerList().clear(); //清除合并区的游戏服列表
			areaBean.setMeraged(true);
			areaBean.set();
		}
		// 更新服务器所属区域
		for (String serverId : serverIdList) {
			ServerBean serverBean = ServerBean.get(serverId);
			if (serverBean == null) {
				continue;
			}
			serverBean.setAreaId(mainAreaBean.getAreaId());
			serverBean.set();
		}
		mainAreaBean.getServerList().clear();
		mainAreaBean.setServerList(serverIdList); //主区，重置游戏服列表
		mainAreaBean.set();

		// 各模块操作
		new MergeAreaHandle_排行榜().handle(mainAreaBean, areas);
		new MergeAreaHandle_排行进度().handle(mainAreaBean, areas);
		new MergeAreaHandle_冲榜排行榜().handle(mainAreaBean, areas);
	}

	public static boolean tryLock(String lockkey) throws InterruptedException {
		RedisConnection redisUser = RedisManager.getInstance().getConnection(RedisType.REDIS_USER);
		RLock lock = redisUser.client().getLock(lockkey);
		return lock.tryLock(20, 10, TimeUnit.SECONDS);
	}

	public static void unlock(String lockkey) {
		try {
			RedisConnection redisUser = RedisManager.getInstance().getConnection(RedisType.REDIS_USER);
			RLock lock = redisUser.client().getLock(lockkey);
			lock.unlock();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public Business clone() throws CloneNotSupportedException {
		return (Business) super.clone();
	}

}
